package nl.iprofs.modules.contextlogging;
/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Hierarchy;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.spi.LoggerRepository;
import org.apache.log4j.spi.RepositorySelector;
import org.apache.log4j.spi.RootLogger;
import org.apache.log4j.xml.DOMConfigurator;

/**
 * This RepositorySelector tries to load a custom log4j config file for different WARs (not the root context).
 * The config file has to be called "[context-root]-log4j.xml" and should be placed on the classpath.
 * 
 * @see <a href="http://community.jboss.org/wiki/log4jrepositoryselector">Example</a>
 * 
 * @author Wouter Zelle
 */
public class Log4jRepositorySelector implements RepositorySelector {
    private static final Log LOG = LogFactory.getLog(Log4jRepositorySelector.class);
    
    private static boolean initialized;
    private static Object guard = LogManager.getRootLogger();
    private static Map<ClassLoader, Hierarchy> repositories = new HashMap<ClassLoader, Hierarchy>();
    private static LoggerRepository defaultRepository;

    public static synchronized void init(ServletConfig servletConfig)
            throws ServletException {
        init(servletConfig.getServletContext());
    }

    public static synchronized void init(ServletContext servletContext)
            throws ServletException {
        if (!initialized) // set the global RepositorySelector
        {
            defaultRepository = LogManager.getLoggerRepository();
            RepositorySelector theSelector = new Log4jRepositorySelector();
            LogManager.setRepositorySelector(theSelector, guard);
            initialized = true;
        }

        Hierarchy hierarchy = loadLog4JConfig(servletContext);
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        repositories.put(loader, hierarchy);
    }

    public static synchronized void removeFromRepository() {
        repositories.remove(Thread.currentThread().getContextClassLoader());
    }

    /**
     * This is where the actual config file is loaded.
     */
    private static Hierarchy loadLog4JConfig(ServletContext servletContext) throws ServletException {
        String contextPath = servletContext.getContextPath();
        if (LOG.isDebugEnabled()) {
            LOG.debug("contextPath: " + contextPath);
        }
        
        if ("".equals(contextPath)) {
            contextPath = "/ROOT";
        }
        String log4jFile =  contextPath + "-log4j.xml";
        if (LOG.isDebugEnabled()) {
            LOG.debug("Log4j Filename: " + log4jFile);
        }

        try {
            InputStream log4JConfigStream = Log4jRepositorySelector.class.getResourceAsStream(log4jFile);
            DOMConfigurator conf = new DOMConfigurator();
            Hierarchy hierarchy = new Hierarchy(new RootLogger(Level.DEBUG));
            conf.doConfigure(log4JConfigStream, hierarchy);
            return hierarchy;
        } catch (Exception e) {
            throw new ServletException("Unable to find/parse log configuration file " + log4jFile, e);
        }
    }

    private Log4jRepositorySelector() {
    }

    public LoggerRepository getLoggerRepository() {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        LoggerRepository repository = (LoggerRepository) repositories.get(loader);
        if (repository == null) {
            return defaultRepository;
        } else {
            return repository;
        }
    }
}
